/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: RxDataScanner
 * @Package com.rx.core.data
 * @Description: RxData 注解扫描
 * @author: 陈锦韬
 * @date: 2020\8\11 0011
 * @version V1.0
 * @Copyright: 2020 陈锦韬  All rights reserved.
 */
package com.rx.core.handler;

import com.rx.core.anno.RxAlias;
import com.rx.core.base.RxBaseConstant;
import com.rx.core.base.RxScanner;
import com.rx.core.enm.HANDLER_CATEGORY;
import com.rx.core.enm.HANDLER_TYPE;
import com.rx.core.enm.RX_LOG_MODE;
import com.rx.core.mode.HandlerContainer;
import com.rx.core.mode.TotalHandlerContainer;
import com.rx.core.util.EmptyChecker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.lang.reflect.Method;

/**
 * @author: Administrator
 * @Description: RxData 注解扫描
 * @date: 2020\8\11 0011
 */
@Slf4j
public class RxHandlerScanner extends RxScanner {

    public RxHandlerScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public static void scan(BeanDefinitionRegistry registry,String[] basePackages){
        RxHandlerScanner scanner = new RxHandlerScanner(registry);
        TypeFilter helloServiceFilter = new AssignableTypeFilter(RxHandler.class);
        scanner.addIncludeFilter(helloServiceFilter);
        // 第二个参数是注解
        scanner.scanRxData(basePackages,RxHandler.class);
        scanner.scan(basePackages);
    }
    private void setAlias(Class cls,String handlerName){
        RxAlias rxAlias = (RxAlias) cls.getAnnotation(RxAlias.class);
        if (EmptyChecker.isEmpty(rxAlias)||EmptyChecker.isEmpty(rxAlias.value())){
            return;
        }
        HandlerContainer.HANDLER_ALIAS.put(rxAlias.value(),handlerName);
    }
    private void setAlias(Method method,String handlerName){
        RxAlias rxAlias = (RxAlias) method.getAnnotation(RxAlias.class);
        if (EmptyChecker.isEmpty(rxAlias)||EmptyChecker.isEmpty(rxAlias.value())){
            return;
        }
        HandlerContainer.HANDLER_ALIAS.put(rxAlias.value(),handlerName);
    }
    @Override
    protected void register(Class<?> loadClass, BeanDefinition candidate){
        urlFormClassMap.put(loadClass.getSimpleName(),loadClass);
        log.info(RX_LOG_MODE.REG_HANDLER.getFormat(),candidate.getBeanClassName());

        if (EmptyChecker.isEmpty(loadClass.getMethods())){
            return;
        }
        RxHandler classAnno = loadClass.getAnnotation(RxHandler.class);
        if(EmptyChecker.notEmpty(loadClass.getInterfaces())){
            for (Class<?> anInterface : loadClass.getInterfaces()) {
                if (anInterface.equals(RxHandlerContent.class)){
                    log.info("============ 继承了接口RxHandlerContent");
                    setAlias(loadClass,loadClass.getName());
                    registerInterfaceHandler(classAnno,loadClass);
                    break;
                }
            }
        }
        // 遍历类中处理器函数。
        for (Method method : loadClass.getMethods()) {
            // 注册覆盖处理器
            overRegister(method,classAnno,null);
            // 注册前处理器
            prevRegister(method,classAnno,null);
            // 注册后处理器
            afterRegister(method,classAnno,null);
        }
    }

    private void registerInterfaceHandler(RxHandler classAnno,Class<?> loadClass){
        if(HANDLER_CATEGORY.PREV.equals(classAnno.category())){
            // 注册前处理器
            prevRegister(null,classAnno,loadClass.getName());
        }else if(HANDLER_CATEGORY.OVER.equals(classAnno.category())){
            // 注册前处理器
            overRegister(null,classAnno,loadClass.getName());
        }else if(HANDLER_CATEGORY.AFTER.equals(classAnno.category())){
            // 注册前处理器
            afterRegister(null,classAnno,loadClass.getName());
        }
    }
    /**
     * 排除某些类型用到处理器。即将不是排除的类型遍历输入一遍
     * @param rxHandler
     */
    private void registerExHandler(RxHandlerInfo rxHandler){
        // 如果设置的types里有 ALL 则适合所有请求类型
        for (HANDLER_TYPE type : rxHandler.getTypes()) {
            if (HANDLER_TYPE.ALL == type){
                rxHandler.setTypes(HANDLER_TYPE.getNormalTypes());
                HANDLER_TYPE[] allType = {HANDLER_TYPE.ALL};
                rxHandler.setTypes(allType);
                break;
            }
        }

        if (EmptyChecker.isEmpty(rxHandler.getExtypes())){
            return;
        }

        rxHandler.setTypes(HANDLER_TYPE.getExTypeList(rxHandler.getExtypes()));
    }

    private RxHandlerWraper buildHandler(RxHandlerInfo rxHandler,Method method,String interfaceName){
        if(EmptyChecker.isEmpty(interfaceName)){
            RxHandlerWraper handler = new RxHandlerMethod(method,rxHandler.getOrder());
            setAlias(method,handler.getHandleName());
            return handler;
        }
        return new RxHandlerInterface(interfaceName,rxHandler.getOrder());
    }

    /**
     * 根据handler-type 将处理器注册到合适的容器中。
     * @param rxHandler
     * @param method
     */
    private void registerNormal(RxHandlerInfo rxHandler,Method method,String interfaceName){
        // 跟进key
        RxHandlerWraper rxHandlerMethod = buildHandler(rxHandler,method,interfaceName);
        for (HANDLER_TYPE type : rxHandler.getTypes()) {
            // 处理器入库
            TotalHandlerContainer.setHandler(rxHandler.getCls(),rxHandlerMethod);
            if(HANDLER_TYPE.NONE == type || null == type){
                continue;
            }
            for (String key : rxHandler.getKeys()) {
                if (RxBaseConstant.DEFAULT_URL_KEY.equalsIgnoreCase(key)){
                    continue;
                }
                rxHandlerMethod.setHandlerType(type,key);
                type.memmory().setHandler(key,rxHandler.getCls(),rxHandlerMethod);
            }
            for (String key : rxHandler.getExkeys()) {
                if (RxBaseConstant.DEFAULT_URL_KEY.equalsIgnoreCase(key)){
                    continue;
                }
                key = HandlerContainer.EXT_PREFIX + key;
                rxHandlerMethod.setHandlerType(type,key);
                type.memmory().setHandler(key,rxHandler.getCls(),rxHandlerMethod);
            }
            if (EmptyChecker.isEmpty(rxHandler.getKeys())&&EmptyChecker.isEmpty(rxHandler.getExkeys())){
                rxHandlerMethod.setHandlerType(type,HandlerContainer.ALL_PREFIX);
                type.memmory().setHandler(HandlerContainer.ALL_PREFIX,rxHandler.getCls(),rxHandlerMethod);
            }
        }
    }

    private void registerProcess(RxHandlerInfo rxHandlerInfo,Method method,String interfaceName){
        registerExHandler(rxHandlerInfo);
        HANDLER_TYPE[] types = rxHandlerInfo.getTypes();
        if (EmptyChecker.isEmpty(types)){
            log.error(RX_LOG_MODE.ERROR.getFormat("处理器未指定类型"));
            return;
        }

        registerNormal(rxHandlerInfo,method,interfaceName);
    }

    private void overRegister(Method method,RxHandler classAnno,String interfaceName){
        if (EmptyChecker.isEmpty(method)){
            registerProcess(RxHandlerInfo.create(classAnno,RxHandler.class),method,interfaceName);
            return;
        }
        RxHandler rxHandler = method.getAnnotation(RxHandler.class);
        if (EmptyChecker.isEmpty(rxHandler)){
            return;
        }
        RxHandlerInfo rxHandlerInfo = RxHandlerInfo.create(rxHandler);
        rxHandlerInfo.overValue(classAnno);
        registerProcess(rxHandlerInfo,method,interfaceName);
    }

    private void prevRegister(Method method,RxHandler classAnno,String interfaceName){
        if (EmptyChecker.isEmpty(method)){
            registerProcess(RxHandlerInfo.create(classAnno,RxHandlerPrev.class),method,interfaceName);
            return;
        }
        RxHandlerPrev rxHandler = method.getAnnotation(RxHandlerPrev.class);
        if (EmptyChecker.isEmpty(rxHandler)){
            return;
        }
        RxHandlerInfo rxHandlerInfo = RxHandlerInfo.create(rxHandler);
        rxHandlerInfo.overValue(classAnno);
        registerProcess(rxHandlerInfo,method,interfaceName);
    }

    private void afterRegister(Method method,RxHandler classAnno,String interfaceName){
        if (EmptyChecker.isEmpty(method)){
            registerProcess(RxHandlerInfo.create(classAnno,RxHandlerAfter.class),method,interfaceName);
            return;
        }
        RxHandlerAfter rxHandler = method.getAnnotation(RxHandlerAfter.class);
        if (EmptyChecker.isEmpty(rxHandler)){
            return;
        }
        RxHandlerInfo rxHandlerInfo = RxHandlerInfo.create(rxHandler);
        rxHandlerInfo.overValue(classAnno);
        registerProcess(rxHandlerInfo,method,interfaceName);
    }

}
